ebooktestfandomcom-20200214-history
Exports and Freezing in the Build
=TARGETTYPEs and Exported Interfaces= This is a short guide outlining the support in Raptor and gives details on exported functions etc and freezing. =TARGETTYPEs and Exported Interfaces in more detail= The vast majority of components built for the Symbian OS are built from .mmp files and, as a result, build in the context of a defined TARGETTYPE. TARGETTYPEs dictate specific traits of the component to be built - the UIDs required/used by default, libraries given priority in linking etc. One such trait relates to how the component's exported interface, if applicable, is defined and controlled by the build system. Broadly speaking, TARGETTYPEs that support an exported interface either have their exports (a) statically defined by the build system or (b) frozen in a .def file that is created and managed by the build system. In the latter case, these TARGETTYPEs support the generation of an import library for other components to link against. In terms of interface, we therefore have three broad categories of TARGETTYPE that have the following default behaviour with regard to their exported interface and import library generation: Group A: The management of an exported interface isn't explicitly required or is not applicable EXE KLIB LIB NONE STDEXE STDLIB No import library is generated. Group B: One or more exports forming the interface are hard-coded by the build system ANI FSY LDD KEXT PLUGIN TEXTNOTIFIER2 PDD PDL VAR VAR2 No import library is generated. Group C: The exported interface is variable and must be maintained in a .def file DLL EXEXP IMPLIB * KDLL STDDLL An import library can be generated assuming that a frozen .def file exists. * IMPLIB is a bit of a special case - its purpose is solely to support the generation of an import library from a pre-existing .def file; it does not support the compile and link of source. =.def File Names and Locations= For components using a TARGETTYPE from group C, the build system implicitly determines .def file name and location using the following logic: Emulator: .mmp file location/../bwins/targetu.def Target: .mmp file location/../eabi/targetu.def There are two keywords that can be used to modify this behaviour, and they can be used in combination: DEFFILE If the value listed by DEFFILE: * solely specifies a path (ends in a slash) then the implicit targetu.def file is assumed to be at this location, relative to the .mmp file. * just specifies a filename (contains no slashes) then the listed filename is assumed to be at the implicit location. * specifies both a path and filename then the listed filename is assumed to be at the path specified, relative to the .mmp file. * contains '~', then '~' will be replaced, according to the build, by 'bwins' or 'eabi'. An additional use of DEFFILE is to coerce TARGETTYPEs from group B, where any exports are statically defined by the build system and a .def file is not normally required, into requiring a .def file, supporting additional exports and generating an import library. This overriding behaviour also applies to EXE and STDEXE TARGETTYPEs from group A, but I can't see any overly good reason to shout about that much ;-). NOSTRICTDEF By default, the build system will assume that any implicit or explicit .def file must physically exist with the letter "u" directly before the extension (a throw-back to the days of narrow/wide non-unicode/unicode builds and their differing exports). With NOSTRICTDEF listed in the .mmp file, this assumption is removed. Example: /src/mycomponent/mycomponent.mmp DEFFILE deffiles/~/mydeffile.def NOSTRICTDEF /src/mycomponent/deffiles/bwins/mydeffile.def /src/mycomponent/deffiles/eabi/mydeffile.def =Freezing Exports= Freezing a component's interface naturally only applies to components that support .def files - so, that amounts to all those using TARGETTYPES from group C above, and those from group B where an explicit DEFFILE statement is present; the build system only generates a FREEZE target for components that match these criteria. The act of freezing involves the build system having knowledge of a component's current exports and, as such, it can only occur in the context of a up-to-date build. Analysis of Current Exports The actual means by which the current exports of a component are determined varies depending on the build being performed. In the emulator build a temporary import library is generated as a side-effect of a "stage one" link where no pre-existing .def file is listed. The import library generated represents the current exports of the component, as it was just built, and this is passed through the linker to generate a .inf file - essentially a text description of the import library's contents. The .inf file is presented to Symbian's MAKEDEF script along with any pre-existing frozen .def file (if one exists) and any static export expectations dervied from the TARGETTYPE (if a group B TARGETTYPE is being built). In the target build the function of the standalone MAKEDEF is performed by ELF2E32 and, as part of post-linking, ELF2E32 determines the state of the current exports versus any pre-existing frozen .def file (if one exists). In both of the above cases a temporary .def file is generated reflecting the current export state and the build system generates errors and warnings depending on how the current situation matches with its expectations. Exports that are identified as missing generate an error - this indicates a break in BC for components already in existence. Exports that are present in addition to those that are expected generate a warning - typically this indicates a component using a group C TARGETTYPE where development has lead to new exports that have not yet been frozen. This does not indicate a BC break for components already in existence, but unfrozen exports will need to frozen in order that (a) they can be managed and validated by the build system and (b) the build system will permit the generation of an import library that includes them. Generating Frozen .def Files In all builds the Symbian EFREEZE script is used to create and update .def files. In Raptor builds, this is invoked in the background in response to the FREEZE target: sbs freeze EFREEZE does its work by analysing the frozen exports in any pre-existing .def file (if present) together with those present in the temporary .def file generated during the build (see above). It then generates a new .def file that reflects the current, validated, exported interface state. There's a further level of validation that also gets applied here... As Symbian interfaces are based on ordinal position rather than name, EFREEZE analyses the temporary .def file reflecting the current exports to conclude whether it includes the same exports, in the same order, as any pre-existing frozen .def file; any difference in the sequence of ordinals versus a frozen .def file is considered an error, and it is not possible to generate a new .def file if this is the case. At least, it's not possible to generate a .def file in what would be considered a normal, default, freeze... EFREEZE also takes on optional "-r" argument. This permits the creation of frozen .def files where missing expected exported functions can be formally flagged as ABSENT (see below), and hence accepted as "absent with leave" in future builds and freezing sessions. EXPORTUNFROZEN By default, the build system will only generate an import library for components using a group C TARGETTYPE, or a group B TARGETTYPE with a DEFFILE statement, if the current exports are frozen within a .def file. In essence this is an attempt to maintain BC by not allowing anything to link to a component that isn't flagging its exports as being managed by the build system. However, this default behaviour can be circumvented if EXPORTUNFROZEN is listed in the .mmp file - regardless of unfrozen exports, EXPORTUNFROZEN will see an import library created, albeit with an appropriate warning. The use of this keyword is really to ease development when the interface of a component is in a state of flux, and it isn't the intention that it is present in production source. It's worth noting here that EXPORTUNFROZEN does not generate an import library without reference to a frozen .def file (if it exists). Rather it generate an import library where any unfrozen exports are reflected after those already represented in any pre-existing .def file. ABSENT Exports and Freezing ABSENT is used within .def files to plug holes where an exported function may no longer be present but, for the purpose of maintaining binary compatibility, the ordinal sequence must be maintained. Below are a couple examples of ABSENT in place in emulator and target .def files (respectively): ?FallBack@CImapSettings@@QBEHXZ @ 39 NONAME ABSENT _ZTIN4Meta11TMetaVarLenI5RBuf8EE @ 5 NONAME ABSENT The second example above is actually pretty representative of most cases of ABSENT that can be found in the core Symbian OS sourcebase. A past change in ARM build behaviour lead to multiple type information and v-table exports no longer being part of the interface of built binaries. However, as these exports had become part of the frozen interface of components, and other "real" function exports had typically been frozen following them, in order to maintain ordinal sequence they were flagged as ABSENT in the relevant .def files. By default, freezing exports using Raptor will not see missing exports automatically ABSENT-ed. In fact, by default, it is considered a fundamental error in the build if exports that were once frozen are found to be missing - usually this has quite serious implications for existing "clients" of DLLs etc, and will result in MAKEDEF and ELF2E32 errors, depending on the build configuration. However, assuming that the impact is known, the process to ABSENT missing exports is as follows: sbs -k sbs -c default.remove_freeze freeze The first step above basically amounts to "Build my component(s) and keep-going - I expect errors due to missing exports, but I need a build of them so that the build system can create a temporary .def file showing the current exports". The second step ensures that, when freezing, the EFREEZE script will be launched with its "-r" option, permitting the ABSENT-ing of exports found the be missing when the current exports are compared to the frozen ones. The sort of errors you will see from the first step will depend on the build configurations processed. For the emulator you should expect to see MAKEDEF errors: MAKEDEF ERROR: 1 Frozen Export(s) missing from object files (POSSIBLE COMPATIBILITY BREAK): M:/src/examples/Basics/bwins/createstaticdllu.def(2) : ?ShowMessage@CMessenger@@QAEXXZ @1 ...and for ARM builds, errors from ELF2E32: elf2e32 : Error: E1036: Symbol _ZN10CMessenger11ShowMessageEv Missing from ELF File : M:/builds/tb101sf/epoc32/release/armv5/udeb/createstaticdll.dll.sym Attempting the second step will show additional EFREEZE output listing the ABSENT-ing of the missing exports: EFREEZE: Marking 1 Export(s) as ABSENT in M:/src/examples/Basics/bwins/createstaticdllu.def : ?ShowMessage@CMessenger@@QAEXXZ @ 1 NONAME ; void CMessenger::ShowMessage(void) EFREEZE: Marking 1 Export(s) as ABSENT in M:/src/examples/Basics/eabi/createstaticdllu.def : _ZN10CMessenger11ShowMessageEv @ 1 NONAME In the above example, both emulator and ARM .def files have been updated to mark the missing ShowMessage(void) export as ABSENT; ordinal 1 will now remain allocated, but ABSENT, and any following exports in the .def files will respect this. TBD After discussing a related issue, it's clear that there's a PREPDEF shaped hole in this story that needs to be filled. Category:Symbian C++